#ifndef _SMART_FD_INNER_HPP_20180919_
#define _SMART_FD_INNER_HPP_20180919_

#include <unistd.h>
#include <cassert>
#include <iostream>
#include <exception>
#include <boost/bind.hpp>
#include <boost/function.hpp>

#define Bind boost::bind
#define Function boost::function

namespace SmartFd {

    typedef Function<void (int fd)> Deleter;
    static void DefaultClose(int fd) {
        std::cout << "close fd:" << fd << std::endl;
        close(fd);
    }

    class SharedDetail
    {
      public:
        SharedDetail(int fd = -1, Deleter del = DefaultClose)
            : fd_(fd), deleter_(del)
            , shared_count_(0), weak_count_(0)
        { }

        ~SharedDetail()
        {
            assert(shared_count_ == 0 && weak_count_ == 0);
        }

        int getFd() const { return fd_; }

        void sharedRef() { ++shared_count_; }
        void sharedUnref()
        {
            if (shared_count_ > 0) {
                --shared_count_;
                if (shared_count_ == 0) {
                    releaseFd();
                }
            }
        }

        void weakRef() { ++weak_count_; }
        void weakUnref()
        {
            if (weak_count_ > 0) {
                --weak_count_;
            }
        }

        int getSharedCount() const { return shared_count_; }
        int getWeakCount() const { return shared_count_; }

        bool anyRef() const { return (shared_count_ + weak_count_) > 0; }

      protected:
        void releaseFd()
        {
            if (fd_ >= 0 && deleter_) {
                deleter_(fd_);
            }
        }

      private:
        int fd_;
        Deleter deleter_;

        int shared_count_;
        int weak_count_;
    };

    class WeakFd;

    class SharedFd
    {
      public:
        SharedFd();
        explicit SharedFd(int fd);
        SharedFd(int fd, SmartFd::Deleter del);
        SharedFd(const SharedFd &other);
        SharedFd(const WeakFd &weak_fd);
        ~SharedFd();

        SharedFd& operator = (const SharedFd &other);
        SharedFd& operator = (const WeakFd &other);

        void swap(SharedFd &other);
        void reset();
        bool empty() const;

        operator int () const;

        bool owner_before(const SharedFd &other) const;
        bool owner_after(const SharedFd &other) const;

      private:
        friend class WeakFd;

        SmartFd::SharedDetail *detail_;
    };

    class WeakFd
    {
      public:
        WeakFd();
        WeakFd(const WeakFd &other);
        WeakFd(const SharedFd &other);
        ~WeakFd();

        WeakFd& operator = (const WeakFd &other);
        WeakFd& operator = (const SharedFd &other);

        void swap(WeakFd &other);
        void reset();

        bool empty() const;
        bool expired() const;

        bool owner_before(const WeakFd &other) const;
        bool owner_after(const WeakFd &other) const;

      private:
        friend class SharedFd;

        SmartFd::SharedDetail *detail_;
    };
}

#endif //_SMART_FD_INNER_HPP_20180919_
